#include "HandShake.hpp"
#include "MiscUtils/TdrMisc/Headers/tFormatter.hpp"

using namespace std;

std::string HandShakeProtocol::getReplies() {
	string ret = "";
	for (int idx = 0; idx < handshakes.size(); idx++) {
		ret += TFormater::toDisplayable(handshakes[idx].result.reply);
	}
	return ret;
}

std::string HandShakeProtocol::getReply(std::string hint) {
	auto shake = getShakeRef(hint);
	if (shake == nullptr) {
		return "";
	}

	auto ret = shake->getReplyStr();
	if (ret.length() > 2) {
		if (TStrTools::endWith(ret, "\\n")) {
			ret = ret.substr(0, ret.length() - 2);
		}
		if (TStrTools::endWith(ret, "\\r")) {
			ret = ret.substr(0, ret.length() - 2);
		}
	}
	return ret;
}

std::string HandShakeProtocol::toStr(int indent) {
	string ret;

	for (int idx = 0; idx < handshakes.size(); idx++) {
		auto& shake = handshakes[idx];
		string block;
		TFormater::indent(indent, block);
		block += "Shake " + TFormater::int2str(idx) + "/" + TFormater::int2str(handshakes.size()) + " (" + shake.hint + ")" + "\n";
		block += shake.toStr(indent + 2);
		ret.append(block);
		//for(int replyIdx=0;replyIdx< shake.exp.possibleReplies.size())
		//ret += ">>" + TFormater::toDisplayable(shake.exp.possibleReplies);
	}

	return ret;
}

int HandShakeProtocol::restart() {
	for (OneShake& handshake : handshakes) {
		handshake.restart();
	}
	return handshakes.size();
}

HandShakeProtocol::OneShake* HandShakeProtocol::getShakeRef(std::string hint) {
	for (OneShake& handshake : handshakes) {
		if (handshake.hint.compare(hint) == 0) {
			return &handshake;
		}
	}
	return nullptr;
}

void HandShakeProtocol::OneShake::restart() {
	result.reset();
}

void HandShakeProtocol::OneShake::set(U8Vec& command, std::string& reply, int timeout) {
	toSend.dataToSend = command;
	exp.set(reply, 0, 0, timeout);
}

std::string HandShakeProtocol::OneShake::toStr(int indent) {
	string ret;

	TFormater::indent(indent, ret);
	ret += "<<" + TFormater::toDisplayable(toSend.dataToSend) + "\n";
	TFormater::indent(indent, ret);

	if (exp.possibleReplies.size() == 1) {
		ret += "? >>" + TFormater::toDisplayable(exp.possibleReplies[0]) + "\n";
	}
	else if (exp.possibleReplies.size() > 1) {
		for (int idx = 0; idx < exp.possibleReplies.size(); idx++) {
			ret += "? #" + TFormater::int2str(idx) + " >>" + TFormater::toDisplayable(exp.possibleReplies[idx]) + "\n";
		}
	}
	else {
		if (exp.replyEnd.size() > 0) {
			ret += "? >>>>" + TFormater::toDisplayable(exp.replyEnd) + "\n";
		}
	}

	if (result.reply.size() > 0) {
		ret += ">>" + TFormater::toDisplayable(toSend.dataToSend) + "\n";
	}

	return ret;
}

void HandShakeProtocol::OneShake::ReplyExp::resize(int size) {
	isReplyTemplate.resize(size);
	possibleReplies.resize(size);
	flagParseNumberInReply.resize(size);
}

HandShakeProtocol::OneShake::ReplyExp::ReplyExp(std::vector<uint8_t> reply, int timeoutIn) {
	set(reply, 0, 0, timeout);
}

void HandShakeProtocol::OneShake::ReplyExp::set(std::vector<uint8_t> reply, int isTemplate, int parseNum, int timeoutIn) {
	timeout = timeoutIn;
	replyEnd = TFormater::str2u8("\n");
	isReplyTemplate.resize(1, isTemplate);
	possibleReplies.resize(1, reply);
	flagParseNumberInReply.resize(1, parseNum);
}

void HandShakeProtocol::OneShake::ReplyExp::set(std::string reply, int isTemplate, int parseNum, int timeoutIn) {
	timeout = timeoutIn;
	replyEnd = TFormater::str2u8("\n");
	isReplyTemplate.resize(1, isTemplate);
	possibleReplies.resize(1, TFormater::str2u8(reply));
	flagParseNumberInReply.resize(1, parseNum);
}

void HandShakeProtocol::OneShake::ReplyExp::add(std::vector<uint8_t> reply, int isTemplate, int parseNum) {
	isReplyTemplate.push_back(isTemplate);
	possibleReplies.push_back(reply);
	flagParseNumberInReply.push_back(parseNum);
}

void HandShakeProtocol::OneShake::ReplyResult::reset() {
	reply.clear();
	replyTypeIdxOut = -1;
	parsedNumberOut.clear();
}

std::string HandShakeProtocol::OneShake::getReplyStr() {
	if (result.reply.size() < exp.replyEnd.size()) {
		return "";
	}
	std::vector<uint8_t> replyCp = result.reply;
	for (int idx = 0; idx < exp.replyEnd.size(); idx++) {
		replyCp.pop_back();
	}
	return TFormater::toDisplayable(replyCp);
}